package at.fpmedv.eclipse.helma.core;

import helma.framework.core.Application;
import helma.framework.repository.FileRepository;
import helma.framework.repository.Repository;
import helma.util.ResourceProperties;
import helma.util.StringUtils;

import java.io.File;
import java.util.ArrayList;

import at.fpmedv.eclipse.helma.preferences.HelmaConstants;

public class HelmaAppDescriptor {
	
    String appName;
    File appDir;
    File dbDir;
    String mountpoint;
    String pathPattern;
    String staticDir;
    String protectedStaticDir;
    String staticMountpoint;
    boolean staticIndex;
    String[] staticHome;
    String xmlrpcHandlerName;
    String cookieDomain;
    String sessionCookieName;
    String protectedSessionCookie;
    String uploadLimit;
    String uploadSoftfail;
    String debug;
    boolean encode;
    Repository[] repositories;

    /**
     * extend apps.properties, add [appname].ignore
     */
    String ignoreDirs;

    /**
     * Creates an AppDescriptor from the properties.
     * @param name the application name
     * @param appsProperties the apps.properties Resource
     */
    public HelmaAppDescriptor(String name, ResourceProperties appsProperties) {
        ResourceProperties conf = appsProperties.getSubProperties(name + '.');
        appName = name;
        mountpoint = getMountpoint(conf.getProperty("mountpoint", appName));
        pathPattern = getPathPattern(mountpoint);
        staticDir = conf.getProperty("static");
        staticMountpoint = getPathPattern(conf.getProperty("staticMountpoint",
                                    joinMountpoint(mountpoint, "static")));
        staticIndex = "true".equalsIgnoreCase(conf.getProperty("staticIndex"));
        String home = conf.getProperty("staticHome");
        if (home == null) {
            staticHome = new String[] {"index.html", "index.htm"};
        } else {
            staticHome = StringUtils.split(home, ",");
        }
        protectedStaticDir = conf.getProperty("protectedStatic");

        cookieDomain = conf.getProperty("cookieDomain");
        sessionCookieName = conf.getProperty("sessionCookieName");
        protectedSessionCookie = conf.getProperty("protectedSessionCookie");
        uploadLimit = conf.getProperty("uploadLimit");
        uploadSoftfail = conf.getProperty("uploadSoftfail");
        debug = conf.getProperty("debug");
        encode = "true".equalsIgnoreCase(conf.getProperty("responseEncoding"));
        String appDirName = conf.getProperty("appdir");
        appDir = (appDirName == null) ? getAbsoluteFile(getHelmaHomePath() + File.separator + "apps" + File.separator + name) : getAbsoluteFile(appDirName);
        String dbDirName = conf.getProperty("dbdir");
        dbDir = (dbDirName == null) ? getAbsoluteFile(getHelmaHomePath() + File.separator + "db" + File.separator + name) : getAbsoluteFile(dbDirName);
        // got ignore dirs
        ignoreDirs = conf.getProperty("ignore");

        // read and configure app repositories
        ArrayList<Repository> repositoryList = new ArrayList<Repository>();
        Class[] parameters = { String.class };
        for (int i = 0; true; i++) {
            String repositoryArgs = conf.getProperty("repository." + i);

            if (repositoryArgs != null) {
                // lookup repository implementation
                String repositoryImpl = conf.getProperty("repository." + i +
                                                          ".implementation");
                if (repositoryImpl == null) {
                    // implementation not set manually, have to guess it
                    if (repositoryArgs.endsWith(".zip")) {
                        repositoryArgs = findResource(repositoryArgs);
                        repositoryImpl = "helma.framework.repository.ZipRepository";
                    } else if (repositoryArgs.endsWith(".js")) {
                        repositoryArgs = findResource(repositoryArgs);
                        repositoryImpl = "helma.framework.repository.SingleFileRepository";
                    } else {
                        repositoryArgs = findResource(repositoryArgs);
                        repositoryImpl = "helma.framework.repository.FileRepository";
                    }
                }

                try {
                    Repository newRepository = (Repository) Class.forName(repositoryImpl)
                            .getConstructor(parameters)
                            .newInstance(new Object[] {repositoryArgs});
                    repositoryList.add(newRepository);
                } catch (Exception ex) {
                	HelmaCorePlugin.getDefault().log("Adding repository " + repositoryArgs + " failed. " +
                                       "Will not use that repository. Check your initArgs!", ex);
                }
            } else {
                // we always scan repositories 0-9, beyond that only if defined
                if (i > 9) {
                    break;
                }
            }
        }

        if (appDir != null) {
            FileRepository appRep = new FileRepository(appDir);
            if (!repositoryList.contains(appRep)) {
                repositoryList.add(appRep);
            }
        } else if (repositoryList.isEmpty()) {
            repositoryList.add(new FileRepository(
                    new File(new File(getHelmaHomePath(), "apps"), appName)));
        }
        repositories = new Repository[repositoryList.size()];
        repositories = (Repository[]) repositoryList.toArray(repositories);
    }
    
    private String getMountpoint(String mountpoint) {
        mountpoint = mountpoint.trim();

        if ("".equals(mountpoint)) {
            return "/";
        } else if (!mountpoint.startsWith("/")) {
            return "/" + mountpoint;
        }

        return mountpoint;
    }
    
    private String getPathPattern(String mountpoint) {
        if (!mountpoint.startsWith("/")) {
            mountpoint = "/"+mountpoint;
        }

        if ("/".equals(mountpoint)) {
            return "/";
        }

        if (mountpoint.endsWith("/")) {
            return mountpoint + "*";
        }

        return mountpoint + "/*";
    }
    
    private String joinMountpoint(String prefix, String suffix) {
        if (prefix.endsWith("/") || suffix.startsWith("/")) {
            return prefix+suffix;
        } else {
            return prefix+"/"+suffix;
        }
    }
    
    private File getAbsoluteFile(String path) {
        // make sure our directory has an absolute path,
        // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4117557
        File file = new File(path);
        if (file.isAbsolute()) {
            return file;
        } else {
            return file.getAbsoluteFile();
        }
    }
    
    private String findResource(String path) {
        File file = new File(path);
        if (!file.isAbsolute() && !file.exists()) {
            file = new File(getHelmaHomePath(), path);
        }
        return file.getAbsolutePath();
    }
    
    /**
     * 
     * @return the path to the helma dir stored in the PreferenceStore of the HelmaCorePlugin
     */
    private String getHelmaHomePath() {
    	return HelmaCorePlugin.getDefault().getPreferenceStore().getString(HelmaConstants.P_HELMA_HOME_PATH);
    }
}
